package cn.xxm.dongbao.user.secure.dos;

import cn.xxm.dongbao.user.secure.access.DefaultAccessDeniedHandlerImpl;
import cn.xxm.dongbao.user.secure.dos.DosConfig;
import cn.xxm.dongbao.user.secure.dos.DosPrecautionFilter;
import cn.xxm.dongbao.user.secure.dos.DosStatisticsException;
import cn.xxm.dongbao.user.secure.dos.DosStatisticsProcess;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * This filter work for Spring framework, because this class extends {@link OncePerRequestFilter}. If the not use the
 * Spring MVC framework, please directly call {@link DosPrecautionFilter}.
 */
public class SpringDosPrecautionFilter extends OncePerRequestFilter {
    private AccessDeniedHandler accessDeniedHandler = null;
    private DosStatisticsProcess process = null;

    /**
     * Construct can be initialized in the spring xml file.
     * @param process Dos statistics process
     */
    public SpringDosPrecautionFilter(DosStatisticsProcess process) {
        this(process, null);
    }

    /**
     * Construct can be initialized in the spring xml file.
     * @param process Dos statistics process
     * @param config Dos config
     */
    public SpringDosPrecautionFilter(DosStatisticsProcess process, DosConfig config) {
        this.process = process;
        setAccessDeniedHandler(new DefaultAccessDeniedHandlerImpl());
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            process.doStatistics(request);
            filterChain.doFilter(request, response);
        } catch (DosStatisticsException e) {
            accessDeniedHandler.handle(request, response, new AccessDeniedException(e.getMessage(), e));
        }
    }

    /**
     * User can set access denied handler
     * @param accessDeniedHandler Access denied handler
     */
    public final void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
        this.accessDeniedHandler = accessDeniedHandler;
    }
}